package org.mili.ticketeer.legacy;

import org.mili.core.xml.XmlAccess;
import org.mili.ticketeer.dao.ModificationResult;
import org.mili.ticketeer.dto.Contact;
import org.mili.ticketeer.dto.SexEnum;
import org.mili.ticketeer.legacy.generated.Action;
import org.mili.ticketeer.legacy.generated.Group;
import org.mili.ticketeer.legacy.generated.Meetings;
import org.mili.ticketeer.legacy.generated.Members;
import org.mili.ticketeer.legacy.generated.ObjectFactory;
import org.mili.ticketeer.legacy.generated.Priority;
import org.mili.ticketeer.legacy.generated.Role;
import org.mili.ticketeer.legacy.generated.Speaker;
import org.mili.ticketeer.legacy.generated.State;
import org.mili.ticketeer.legacy.generated.Ticket;
import org.mili.ticketeer.legacy.generated.Tickets;
import org.mili.ticketeer.service.ActionService;
import org.mili.ticketeer.service.ContactService;
import org.mili.ticketeer.service.GroupService;
import org.mili.ticketeer.service.MeetingService;
import org.mili.ticketeer.service.MigrationService;
import org.mili.ticketeer.service.PriorityService;
import org.mili.ticketeer.service.RoleService;
import org.mili.ticketeer.service.ServiceException;
import org.mili.ticketeer.service.ServiceFactory;
import org.mili.ticketeer.service.StateService;
import org.mili.ticketeer.service.TicketService;

import javax.xml.bind.JAXBElement;
import java.io.File;
import java.io.Serializable;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

public class LegacyImport {
    private final static ObjectFactory factory = new ObjectFactory();
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
    private static ContactService contactService = ServiceFactory.getService(ContactService.class);
    private static RoleService roleService = ServiceFactory.getService(RoleService.class);
    private static MeetingService meetingService = ServiceFactory.getService(MeetingService.class);
    private static PriorityService priorityService = ServiceFactory.getService(PriorityService.class);
    private static StateService stateService = ServiceFactory.getService(StateService.class);
    private static TicketService ticketService = ServiceFactory.getService(TicketService.class);
    private static ActionService actionService = ServiceFactory.getService(ActionService.class);

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            Tickets tickets = (Tickets) XmlAccess.read(new File("../tickets.xml"),
                    "org.mili.ticketeer.legacy.generated");

            ServiceFactory.getService(MigrationService.class).migrate(true);

            // migrate speakers
            migrateSpeakers(tickets.getMembers());

            // prios
            migratePrios();

            // states
            migrateStates();

            // migrate groups
            migrateGroups(tickets.getGroup());
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    private static void migratePrios() throws ServiceException {
        for (Priority p : Priority.values()) {
            org.mili.ticketeer.dto.Priority priority = new org.mili.ticketeer.dto.Priority();
            priority.setName(p.name());
            priority.setPriority(3 - p.ordinal());
            priorityService.write(priority);
        }
    }

    private static void migrateStates() throws ServiceException {
        for (State s : State.values()) {
            org.mili.ticketeer.dto.State state = new org.mili.ticketeer.dto.State();
            state.setToken(s.name());
            state.setTitle(getState(s));
            stateService.write(state);
        }
    }

    private static String getState(State state) {
        String s;
        switch(state) {
            case A:
                s = "Aufgenommen";
                break;
            case C:
                s = "Abgelehnt";
                break;
            case W:
                s = "In Bearbeitung";
                break;
            case R:
                s = "Rückfrage";
                break;
            case D:
                s = "Erledigt";
                break;
            case F:
                s = "Prüfung";
                break;
            default:
                throw new IllegalArgumentException("no state!");
        }
        return s;
    }

    private static void migrateGroups(List<Group> groups) throws ServiceException {
        GroupService groupService = ServiceFactory.getService(GroupService.class);
        for (Group g : groups) {
            org.mili.ticketeer.dto.Group group = new org.mili.ticketeer.dto.Group();
            group.setName(g.getName());
            ModificationResult modificationResult = groupService.write(group);
            group.setId(modificationResult.getId());

            migrateTickets(group, g.getTicket());
        }
    }

    private static void migrateTickets(org.mili.ticketeer.dto.Group group, List<Ticket> tickets) throws ServiceException {
        for (Ticket t : tickets) {
            org.mili.ticketeer.dto.Ticket ticket = new org.mili.ticketeer.dto.Ticket();
            ticket.setPriority(priorityService.findByName(t.getPriority().name()).getId());

            ticket.setCompletedAt(getDate(t.getCompleted()));
            ticket.setCreatedAt(getDate(t.getCreated()));
            ticket.setGroup(group.getId());
            ticket.setState(stateService.findByToken(t.getState().name()).getId());
            ticket.setTitle(t.getTitle());
            ticket.setGroup(group.getId());

            List<Action> actions = new ArrayList<>();
            for(Serializable serializable : t.getContent()) {
                if (serializable instanceof JAXBElement) {
                    JAXBElement element = (JAXBElement) serializable;
                    actions.add((Action) element.getValue());
                } else {
                    ticket.setComment(serializable.toString());
                }
            }

            ModificationResult modificationResult = ticketService.write(ticket);
            ticket.setId(modificationResult.getId());

            String[] contacts = t.getContact().split("[,/]");
            for (String co : contacts) {
                Contact contact = contactService.findByLastName(co);
                if (contact == null) {
                    contact = createContact(co);
                }
                ticketService.assign(contact, ticket);
            }

            for (Action a : actions) {
                org.mili.ticketeer.dto.Action action = new org.mili.ticketeer.dto.Action();
                action.setTicket(ticket.getId());
                action.setTitle(a.getTitle());
                action.setComment(a.getContent());
                action.setDate(getDate(a.getDate()));

                modificationResult = actionService.write(action);
                action.setId(modificationResult.getId());

                contacts = a.getContact().split("[,/]");
                for (String co : contacts) {
                    Contact contact = contactService.findByLastName(co);
                    if (contact == null) {
                        contact = createContact(co);
                    }
                    actionService.assign(contact, action);
                }
            }
        }
    }

    private static Contact createContact(String co) throws ServiceException {
        Contact contact = new Contact();
        contact.setFirstName("");
        contact.setLastName(co);
        contact.setStreet("");
        contact.setNumber("");
        contact.setZip(13585);
        contact.setSex(SexEnum.FEMALE);
        contact.setPhone("");
        contact.setEmail("");
        contact.setToken("");
        ModificationResult modificationResult = contactService.write(contact);
        contact.setId(modificationResult.getId());
        return contact;
    }

    private static Timestamp getDate(String date) {
        String[] array = date.split("[.]");
        if (array.length == 3) {
            int year = Integer.valueOf(array[2]);
            if (year < 100) {
                year += 2000;
            }
            GregorianCalendar gregorianCalendar = new GregorianCalendar(year, Integer.valueOf(array[1]) - 1,
                    Integer.valueOf(array[0]));
            return new Timestamp(gregorianCalendar.getTimeInMillis());
        }
        return null;
    }

    private static void migrateSpeakers(Members members) throws ServiceException {
        for (Speaker s : members.getSpeaker()) {

            org.mili.ticketeer.dto.Contact contact = new org.mili.ticketeer.dto.Contact();
            contact.setFirstName(s.getFirstname());
            contact.setLastName(s.getLastname());
            contact.setStreet(s.getStreet());
            contact.setNumber(s.getStreetNumber());
            contact.setActive(true);
            String sex = s.getSex().value().toLowerCase();
            contact.setSex("m".equals(sex) ? SexEnum.MALE : SexEnum.FEMALE);
            contact.setPhone(s.getPhone());
            contact.setEmail(s.getEmail());
            contact.setToken(s.getFirstname().substring(0, 1) + s.getLastname().substring(0, 1));
            contact.setZip(13585);
            contact.setSpeaker(true);

            ModificationResult modificationResult = contactService.write(contact);
            contact.setId(modificationResult.getId());

            // roles
            for (Role r : s.getRole()) {
                org.mili.ticketeer.dto.Role role = roleService.findRoleByName(r.getContent());
                if (role == null) {
                    role = new org.mili.ticketeer.dto.Role();
                    role.setName(r.getContent());
                    ModificationResult modificationResult1 = roleService.write(role);
                    role.setId(modificationResult1.getId());
                }
                roleService.assign(contact, role);
            }

            // meetings
            for (Meetings m : s.getMeetings()) {
                int year = Integer.parseInt(m.getYear());
                String[] array = m.getContent().split("[,]");
                for (String element : array) {
                    int month = Integer.parseInt(element);
                    int date = getDate(year, month);
                    meetingService.assign(contact, date);
                }
            }

        }
    }

    private static int getDate(int year, int month) {
        GregorianCalendar gregorianCalendar = new GregorianCalendar();
        gregorianCalendar.set(year, month - 1, 1);
        int two = 0;
        while (two < 2) {
            gregorianCalendar.roll(GregorianCalendar.DAY_OF_MONTH, 1);
            if (gregorianCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY) {
                two ++;
            }
        }
        gregorianCalendar.set(year, month - 1, gregorianCalendar.get(Calendar.DAY_OF_MONTH));
        return Integer.parseInt(simpleDateFormat.format(gregorianCalendar.getTime()));
    }

}
